<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>im前端测试</title>
    <link rel="stylesheet" href="static/css/element-ui.css">
    <link rel="stylesheet" href="static/css/common.css">
    <style>
        *{padding:0;margin:0;}
        .fl{display: flex;align-items: center;justify-content: flex-start;box-sizing: border-box;}
        .fc{display: flex;align-items: center;justify-content: center;box-sizing: border-box;}
        .fr{display: flex;align-items: center;justify-content: flex-end;box-sizing: border-box;}
        .btn:hover{cursor: pointer;}
        #app{display: none;}
        .chat-wrapper{position:fixed;left:50%;top:50%;transform: translate(-50%,-50%);}
        .chat{background: #f4f4f4;width:70vw;height:80vh;min-height: 500px;min-width: 600px;border-radius: 5px;border:1px solid #eee;overflow: hidden;align-items: flex-start;/*transition: all .4s cubic-bezier(.645,.045,.355,1);*/}
        .chat-nav{flex:0 0 66px;background: #66b1ff;height:100%;flex-direction: column;padding:30px 0;box-sizing: border-box;}
        .chat-nav-avatar{width:40px;height:40px;border-radius: 5px;}
        .chat-nav-item{padding:2px 0;width: 100%;}
        .chat-nav-item-bg{width:56px;padding:10px 0;}
        .chat-nav-item-bg:hover, .chat-nav-item-active{cursor: pointer;background: #f8f8f8;border-radius: 5px 0 0 5px;}
        .chat-nav-icon{color:#fff;font-size: 26px;}
        .chat-nav-item-bg:hover .chat-nav-icon,.chat-nav-item-active .chat-nav-icon{color:#3a8ee6;font-size: 26px;}
        .chat-nav-item-bg:hover path,.chat-nav-item-active path{fill:#3a8ee6;}
        .chat-social{flex:0 0 260px;width:260px;background: #f8f8f8;border-right: 1px solid #e0e0e0;height:100%;}


        .chat-msg-item{margin-bottom:20px;align-items: flex-start;}
        .chat-msg-time{padding:10px;color:#808080;font-size: 12px;}
        .chat-msg-state{padding:0 5px;font-size:12px;color:red;}
        .chat-msg-name{font-size:12px;color:#8a8a8a;padding:2px;}
        .chat-msg-content{border-radius: 8px;padding:10px;align-items: flex-end;position: relative;font-size: 14px;}
        .chat-msg-recv .chat-msg-content{background: #fff;}
        .chat-msg-send .chat-msg-content{background: #95EC69;}
        .chat-msg-avatar{width:50px;height:50px;flex-shrink:0;border-radius: 10px;color:#fff;}
        .chat-msg-recv .chat-msg-avatar{margin-right:10px;}
        .chat-msg-send .chat-msg-avatar{margin-left:10px;}
        .chat-msg-recv .chat-msg-content::after {content: '';position: absolute;width: 0;height: 0;border-top: 5px solid transparent;border-bottom: 5px solid transparent;border-right: 5px solid #fff;left: -5px;top: 8px;}
        .chat-msg-send .chat-msg-content::after {content: '';position: absolute;width: 0;height: 0;border-top: 5px solid transparent;border-bottom: 5px solid transparent;border-left: 5px solid #95EC69;right: -5px;top: 8px;}
        .chat-msg-state{font-size: 11px;height:18px;width:100%;align-items: flex-end;}
        .chat-msg-state .state0{color:#3a8ee6;}
        .chat-msg-state .state1{color:#909090;}
        .chat-msg-state .state2{color:#3a8ee6;}

        .chat-content{box-sizing: border-box;height:100%;width: 100%;position: relative;}
        .chat-content-target{border-bottom: 1px solid #ccc;flex:0 0  50px;}
        .chat-content-target-name{height:50px;padding:0 20px;}
        .chat-content-target-more{height:100%;padding:0 10px;}
        .chat-conv-msg-wrapper{flex-grow: 1;width: 100%;box-sizing: border-box;padding:0 15px;position: relative;overflow: hidden;}
        .chat-conv-msg{width:100%;height:100%;overflow-y:auto;}
        .chat-conv-msg-new-bottom{position: absolute;bottom:10px;left:50%;transform: translateX(-50%);color:#3a8ee6;font-size: 13px;box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.3);padding:5px 15px;border-radius: 30px;z-index:3;}
        .chat-conv-msg-new-bottom-icon{transform: rotate(90deg);font-size: 16px;margin-right:5px;}
        .chat-content-drawer{position: absolute;top:50px;right:0;width:200px;background: #fff;z-index:3;height:100%;border:1px solid #eee;border-top-color: #ccc;}
        .chat-conv-del{padding-top:30px;}
        /* 过渡效果的定义 */
        .slide-right-enter-active, .slide-right-leave-active {
            transition: all 0.5s ease; /* 动画持续时间和缓动效果 */
        }

        /* 进入时的初始状态 */
        .slide-right-enter {
            transform: translateX(100%);
            opacity: 0;
        }

        /* 离开时的状态 */
        .slide-right-leave-to {
            transform: translateX(100%);
            opacity: 0;
        }

        .chat-content-friend{height:100%;}
        .chat-content-conv{height:100%;display: flex;flex-direction: column;}
        .chat-conv{height:100%;}
        .chat-conv-input {width: 100%;flex-grow:1;border: none;padding: 5px;resize: none;overflow-y: auto;box-sizing: border-box;white-space: pre-wrap;word-break: break-word;}
        .chat-conv-input:focus {outline: none;}
        .chat-conv-form{flex:0 0 200px;display: flex;flex-direction: column;border-top:1px solid #ccc;}
        .chat-conv-tool{flex:0 0 40px;box-sizing: border-box;padding:5px 10px;}
        .chat-conv-tool-btn{font-size: 24px;color:#444;}
        .chat-conv-tool-btn:hover{cursor: pointer;}
        .chat-conv-tool-item{margin-right:10px;}
        .social-search{padding:0 15px;height:50px;border-bottom: 1px solid #e0e0e0;}
        .friend-new{padding:10px 20px;border-bottom: 1px solid #e0e0e0;}
        .friend-new-num{flex:0 0 25px;width:25px;height:25px;background: #f56c6c;border-radius: 50%;color:#fff;font-size: 12px;}
        .friend-item{padding:10px;}
        .friend-avatar{flex:0 0 32px;margin-right:6px;border-radius: 6px;width:32px;height:32px;}
        .friend-avatar-text{font-size: 24px;background: #3a8ee6;color:#fff;}
        .friend-name{font-size: 15px;overflow: hidden; white-space: nowrap; text-overflow: ellipsis;}
        .friend-add-search-list{padding-top:10px;}

        .chat-friend-list .active{background: #eee;}
        .friend-detail{}
        .friend-detail-user{padding:30px;}

        .friend-detail-avatar{argin-right:6px;border-radius: 6px;width:80px;height:80px;}
        .friend-detail-avatar-text{font-size: 40px;background: #3a8ee6;color:#fff;}
        .friend-detail-name{font-size: 28px;overflow: hidden; white-space: nowrap; text-overflow: ellipsis;}
        .friend-detail-tochat{position: absolute;bottom:30px;left: 0;width:100%;}


        .search-result{padding:50px 30px;}

        .conv-list{overflow-y:auto;height: 100%;}
        .conv-list .active{background: #eee;}
        .conv-item{padding:10px;width:100%;}
        .conv-item:hover{cursor: pointer;}
        .conv-avatar-wrapper{position: relative;margin-right:10px;}
        .conv-new-num1{position:absolute;right:-5px;top:-5px;width: 18px;height:18px;background: #f56c6c;border-radius: 50%;color:#fff;font-size: 11px;}
        .conv-new-num2{position:absolute;right:-10px;top:-8px;padding:0 5px;height:18px;background: #f56c6c;border-radius: 40%;color:#fff;font-size: 11px;}
        .conv-avatar{flex:0 0 40px;border-radius: 6px;width:40px;height:40px;}
        .conv-avatar-text{font-size: 24px;background: #3a8ee6;color:#fff;}
        .conv-content{flex-grow: 1;overflow: hidden;}
        .conv-content-top{height:25px;}
        .conv-name{font-size: 16px;overflow: hidden; white-space: nowrap; text-overflow: ellipsis;}
        .conv-date{font-size: 11px;color:#bbb;max-width: 70px;}
        .conv-content-bottom{height:22px;}
        .conv-chat{overflow: hidden; white-space: nowrap; text-overflow: ellipsis;font-size: 12px;color:#8a8a8a;}

    </style>
</head>
<body>
<div id="app" ref="app">
    <div v-if="userInfo.id" style="position: absolute;bottom:0;text-align: center;padding:30px;width:100%;box-sizing: border-box;">当前用户：{{userInfo.phone}}</div>
    <div class="chat-wrapper" @click="tapChatWindow">
        <div class="fl chat">
            <div class="chat-nav fl" ref="chatNav">
                <div class="chat-nav-avatar fc" style="background: #fff;color:#3a8ee6;margin-bottom:20px;">我</div>

                <div class="fr chat-nav-item" @click="tapNav('conv')">
                    <div class="fc chat-nav-item-bg" :class="{'chat-nav-item-active':currNav == 'conv'}">
                        <el-badge :value="unreadNewFriendApply" :hidden="unreadConvTotal == 0" :is-dot="false">
                            <i class="el-icon-chat-line-round chat-nav-icon"></i>
                        </el-badge>
                    </div>
                </div>
                <div class="fr chat-nav-item"  @click="tapNav('friend')">
                    <div class="fc chat-nav-item-bg" :class="{'chat-nav-item-active':currNav == 'friend'}">
                        <el-badge :value="unreadNewFriendApply" :hidden="unreadNewFriendApply == 0" :is-dot="false">
                            <i class="el-icon-user-solid chat-nav-icon"></i>
                        </el-badge>
                    </div>
                </div>
                <div class="fr chat-nav-item" @click="tapNav('group')">
                    <div class="fc chat-nav-item-bg" :class="{'chat-nav-item-active':currNav == 'group'}">
                        <el-badge :value="unreadNewGroupApply" :hidden="unreadNewGroupApply == 0" :is-dot="false">
                            <svg t="1723361490120" class="chat-nav-item-group" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5565" width="30" height="30"><path d="M575.457882 507.512471c59.226353-23.476706 101.285647-81.212235 101.285647-148.690824 0-88.229647-71.785412-160-160.015058-160s-160 71.770353-160 160c0 67.478588 42.044235 125.214118 101.270588 148.690824-131.689412 27.226353-231.002353 144.097882-231.002353 283.738353 0 33.957647 23.823059 45.206588 42.962823 54.241882l1.099295 0.451765c77.176471 27.241412 188.792471 34.499765 242.582588 34.499764 58.654118 0 173.477647-9.517176 249.735529-35.855059 28.581647-10.962824 43.083294-28.912941 43.083294-53.338352 0-139.655529-99.312941-256.527059-231.002353-283.738353z" p-id="5566" fill="#fff"></path><path d="M382.780235 494.034824c-37.903059-35.343059-61.741176-85.564235-61.741176-141.477648 0-68.472471 35.644235-128.512 89.283765-162.93647v-0.015059c-0.331294-0.466824-0.813176-0.737882-1.189648-1.129412-0.391529-0.421647-0.632471-0.948706-1.099294-1.325176a160.301176 160.301176 0 0 0-100.141176-35.312941c-88.229647 0-160.015059 71.770353-160.015059 160 0 67.478588 42.059294 125.214118 101.285647 148.690823C117.458824 487.755294 18.160941 604.626824 18.160941 744.267294c0 24.440471 14.501647 42.375529 43.459765 53.488941 42.887529 14.817882 96.105412 23.356235 134.128941 27.994353a322.409412 322.409412 0 0 1-2.409412-38.731294c0-130.439529 77.778824-242.642824 189.44-292.98447zM786.808471 460.544c59.226353-23.476706 101.285647-81.212235 101.285647-148.690824 0-88.229647-71.785412-160-160.015059-160-36.939294 0-73.005176 12.905412-101.51153 36.321883l-4.246588 3.478588a193.400471 193.400471 0 0 1 85.940706 160.903529c0 55.913412-23.838118 106.134588-61.741176 141.477648 111.661176 50.341647 189.44 162.544941 189.44 292.98447 0 13.402353-0.918588 26.578824-2.499765 39.544471l0.798118-0.090353c39.137882-4.547765 95.216941-13.206588 140.483764-28.852706 28.581647-10.962824 43.083294-28.912941 43.083294-53.338353 0-139.655529-99.312941-256.527059-231.017411-283.738353z" p-id="5567" fill="#fff"></path></svg>
                        </el-badge>
                    </div>
                </div>
                <div class="fr chat-nav-item" @click="tapNav('llm')">
                    <div class="fc chat-nav-item-bg" :class="{'chat-nav-item-active':currNav == 'llm'}">
                        <svg t="1730516950798" class="chat-nav-item-group" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11972" width="32" height="32"><path d="M539.70311902 245.19566222v-71.19960494c21.23042765-12.55702124 34.30526419-35.7292563 34.17581037-60.84329876 0.25890765-38.05942518-29.64492642-69.1283437-66.79817482-69.51670519-17.86462815 0.12945383-34.95253333 7.63777581-47.50955457 20.58315852a69.30957906 69.30957906 0 0 0-19.28862025 48.93354667c0 26.02021925 13.72210569 48.54518518 33.91690272 60.58439111v71.32905876H236.39280197c-111.0713837 0-201.04179358 93.72457086-201.1712474 209.45629236v284.66896592c0 115.60226765 89.97040987 209.45629235 201.04179358 209.58574616h541.37590518c110.94192987-0.12945383 200.91233975-93.98347852 200.91233976-209.58574616V454.65195457c-0.12945383-115.60226765-90.0998637-209.32683852-201.04179359-209.45629235H539.70311902zM329.08174222 516.2719763c43.10812445 0.38836148 77.80175013 36.50597925 77.54284247 80.64973431 0.38836148 44.27320889-34.30526419 80.39082667-77.54284247 80.77918815-20.71261235-0.12945383-40.64850173-8.80286025-55.14733037-23.94895801-14.49882864-15.14609778-22.65441975-35.59980247-22.52496593-56.83023014-0.25890765-44.14375506 34.56417185-80.26137283 77.6722963-80.64973431z m355.22130173 0c43.10812445 0.38836148 77.80175013 36.50597925 77.54284247 80.64973431 0 32.75181827-18.90025876 62.13783703-47.76846223 74.56540445-28.99765728 12.55702124-62.52619852 5.56651457-84.53334913-17.34681284-22.26605827-23.30168889-28.86820347-57.99531457-16.82899753-88.1580563 11.78029827-29.90383408 40.13068642-49.58081581 71.58796642-49.71026962z m0 0" p-id="11973" fill="#ffffff"></path></svg>
                    </div>
                </div>
                <div class="fc chat-nav-item" style="position: absolute;bottom:20px;width:50px;">
                    <div class="fc btn"  @click="tapNav('logout')">
                        <svg t="1723363168072" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6614" width="25" height="25"><path d="M512 0c30.72 0 51.2 20.48 51.2 51.2v307.2c0 30.72-20.48 51.2-51.2 51.2s-51.2-20.48-51.2-51.2V51.2c0-30.72 20.48-51.2 51.2-51.2z" fill="#ffffff" p-id="6615"></path><path d="M512 1024C230.4 1024 0 793.6 0 512c0-158.72 71.68-302.08 194.56-399.36 20.48-15.36 56.32-15.36 71.68 10.24 15.36 20.48 10.24 51.2-10.24 66.56C158.72 271.36 102.4 389.12 102.4 512c0 225.28 184.32 409.6 409.6 409.6s409.6-184.32 409.6-409.6c0-128-56.32-240.64-153.6-322.56-20.48-15.36-25.6-51.2-10.24-71.68 15.36-20.48 51.2-25.6 71.68-10.24 122.88 102.4 194.56 245.76 194.56 404.48 0 281.6-230.4 512-512 512z" fill="#ffffff" p-id="6616"></path></svg>
                    </div>
                </div>
            </div>
            <div class="chat-social">
                <div class="chat-conv" v-if="currNav == 'conv'">
                    <div class="social-search fl">
                        <el-input size="mini" prefix-icon="el-icon-search" clearable placeholder="搜索聊天" v-model="searchConvVal" style="margin-right:10px;"></el-input>
                        <el-button size="mini" circle icon="el-icon-plus" class="conv-search-add" @click="tapShowConvAdd"></el-button>
                    </div>
                    <div class="conv-list">
                        <div class="fl conv-item-wrapper" :class="{active:index == activeConvIndex}" @click="tapConvItem(index)" v-for="(item,index) in convList" :key="item.id">
                            <div class="fl conv-item" v-if="item.isShow && item.chatType == 2">
                                <div class="conv-avatar-wrapper">
                                    <div class="fc conv-new-num1" v-if="item.unread > 0 && item.unread < 10">{{item.unread}}</div>
                                    <div class="fc conv-new-num2" v-if="item.unread >= 10 && item.unread < 100">{{item.unread}}</div>
                                    <div class="fc conv-new-num2" v-if="item.unread >= 100">99+</div>
                                    <img v-if="friendObj[item.targetId] && friendObj[item.targetId].friendAvatarImg" :src="friendObj[item.targetId].friendAvatarImg" class="conv-avatar"  />
                                    <div class="conv-avatar conv-avatar-text fc" v-if="friendObj[item.targetId] && !friendObj[item.targetId].friendAvatarImg">{{friendObj[item.targetId].friendName.substring(0,1).toUpperCase()}}</div>
                                </div>
                                <div class="conv-content">
                                    <div class="fb conv-content-top">
                                        <div class="conv-name" v-if="friendObj[item.targetId]">{{friendObj[item.targetId].friendAlias ? friendObj[item.targetId].friendAlias : friendObj[item.targetId].friendName}}</div>
                                        <div class="conv-date">{{formatConvTime(item.lastAtMs)}}</div>
                                    </div>
                                    <div class="fl conv-content-bottom">
                                        <div class="conv-chat" v-if="activeConvIndex !== index && item.inputMsg"><span style="color:red;padding-right:4px;">[草稿]</span>{{item.inputMsg}}</div>
                                        <div class="conv-chat" v-if="item.lastMsg">{{item.lastMsg.msgContent}}</div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="chat-conv" v-if="currNav == 'llm'">
                    <div class="conv-list" style="padding-top:10px;">
                        <div class="fl conv-item-wrapper" :class="{active:index == activeLlmConvIndex}" @click="tapLlmConvItem(index)" v-for="(item,index) in llmConvList" :key="item.id">
                            <div class="fl conv-item">
                                <div class="conv-content">
                                    <div class="fb conv-content-top">
                                        <div class="conv-llm" style="">{{item.name}}</div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="chat-friend" v-if="currNav == 'friend'">
                    <div class="social-search fl">
                        <el-input size="mini" prefix-icon="el-icon-search" clearable placeholder="搜索好友" v-model="searchFriendVal" ref="searchFriendVal" style="margin-right:10px;"></el-input>
                        <el-button size="mini" circle icon="el-icon-plus" class="conv-search-add" @click="tapShowFriendAdd"></el-button>
                    </div>
                    <div class="fb btn friend-new" @click="tapShowFriendNewApply">
                        <div class="fl friend-new-text">新朋友</div>
                        <el-badge style="margin-top:5px;" v-if="unreadNewFriendApply > 0" :value="unreadNewFriendApply"  :max="99"></el-badge>
                    </div>
                    <div class="chat-friend-list">
                        <div class="fl btn friend-item" :class="{active:activeFriendIndex === index}" v-for="(item,index) in friendListCpd" :key="item.id" @click="tapFriendItem(index)">
                            <img :src="item.friendAvatarImg" class="friend-avatar" v-if="item.friendAvatarImg" />
                            <div class="friend-avatar friend-avatar-text fc" v-if="!item.friendAvatarImg">{{item.friendName.substring(0,1).toUpperCase()}}</div>
                            <div class="friend-name">{{item.friendAlias ? item.friendAlias : item.friendName}}</div>
                        </div>
                    </div>
                </div>
                <div class="chat-group" v-if="currNav == 'group'">
                    群组
                </div>
            </div>
            <div class="chat-content">
                <div v-if="currNav == 'conv'">
                    <transition name="slide-right" >
                        <div class="chat-content-drawer" v-if="showConvDrawer" ref="convDrawer">
                            <div class="fc chat-conv-del"><el-button type="danger" @click="tapDelConv">删除聊天</el-button></div>
                        </div>
                    </transition>
                </div>
                <div class="chat-content-conv" v-if="currNav == 'conv' && activeConvIndex > -1">
                    <div class="fb chat-content-target">
                        <div class="fl chat-content-target-name">{{friendObj[convList[activeConvIndex].targetId].friendAlias ? friendObj[convList[activeConvIndex].targetId].friendAlias : friendObj[convList[activeConvIndex].targetId].friendName}}</div>
                        <div class="fl btn chat-content-target-more" @click="showConvDrawer = true" ref="convDrawerBtn"><i class="el-icon-more"></i></div>
                    </div>
                    <div class="chat-conv-msg-wrapper">
                        <div class="fc chat-conv-msg-new-bottom btn" v-if="showChatWindowMoreBottom" @click.stop="tapChatWindowMoreBottom">
                            <i class="chat-conv-msg-new-bottom-icon el-icon-d-arrow-right "></i> {{convList[activeConvIndex].unread}}条新消息
                        </div>
                        <div class="chat-conv-msg" ref="chatConvMsgWindow" @scroll="onChatConvMsgListScroll">
                            <div class="chat-msg-item" v-for="(item,index) in convList[activeConvIndex].msgList" :key="item.id"
                                 :ref="'msgItem_' + index">
                                <div class="fc chat-msg-time" v-if="item.isShowTime">{{formatConvTime(item.sendTime)}}</div>
                                <div class="fr chat-msg-item chat-msg-send" v-if="item.sendId == userInfo.id">
                                    <div class="chat-msg-wrapper">
                                        <div class="fl chat-msg-content">{{item.msgContent}}</div>
                                        <div class="fr chat-msg-state">
                                            <div v-if="item.msgState == 0" class="state0">未读</div>
                                            <div v-if="item.msgState == 1" class="state1">已读</div>
                                        </div>
                                    </div>
                                    <img :src="userInfo.avatarImg" class="chat-msg-avatar" v-if="userInfo.avatarImg" />
                                    <div class="chat-msg-avatar friend-avatar-text fc" v-if="!userInfo.avatarImg">{{userInfo.nickname.substring(0,1).toUpperCase()}}</div>
                                </div>
                                <div class="fl chat-msg-item chat-msg-recv" v-if="item.sendId != userInfo.id">
                                    <img :src="friendObj[item.sendId].friendIcon" class="chat-msg-avatar" v-if="friendObj[item.sendId].friendIcon" />
                                    <div class="chat-msg-avatar friend-avatar-text fc" v-if="!friendObj[item.sendId].friendIcon">{{friendObj[item.sendId].friendName.substring(0,1).toUpperCase()}}</div>
                                    <div class="chat-msg-wrapper">
                                        <div class="fl chat-msg-name">{{friendObj[item.sendId].friendName}}</div>
                                        <div class="fl chat-msg-content">{{item.msgContent}}</div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <div class="chat-conv-form">
                        <div class="fb chat-conv-tool">
                            <div class="fl">
                                <div class="chat-conv-tool-item"><i class="el-icon-picture-outline chat-conv-tool-btn"></i></div>
                                <div class="chat-conv-tool-item"><i class="el-icon-chat-dot-round chat-conv-tool-btn"></i></div>
                            </div>
                            <div class="fl">
                                <div style="color:#ccc;font-size: 14px;">使用Enter键发送消息</div>
                            </div>
                        </div>
                        <div class="chat-conv-input" contenteditable="true" placeholder="按回车键可以发送"  @input="chatInputUpdate" @compositionstart="chatCompositionStart" @compositionend="chatCompositionEnd"  @keydown="chatInputEnter" ref="chatInput"></div>
                    </div>
                </div>
                <div class="chat-content-conv" v-if="currNav == 'llm'">
                    <div class="fb chat-content-target">
                        <div class="fl chat-content-target-name">会话：1</div>
                        <div class="fl btn chat-content-target-more" @click="showConvDrawer = true" ref="convDrawerBtn"><i class="el-icon-more"></i></div>
                    </div>
                    <div class="chat-conv-msg-wrapper" v-if="llmConvListCurrId">
                        <div class="fc chat-conv-msg-new-bottom btn" v-if="showChatWindowMoreBottom" @click.stop="tapChatWindowMoreBottom">
                            <i class="chat-conv-msg-new-bottom-icon el-icon-d-arrow-right "></i> {{llmConvList[activeLlmConvIndex].unread}}条新消息
                        </div>
                        <div class="chat-conv-msg" ref="chatConvMsgWindow">
                            <div class="chat-msg-item" v-for="(item,index) in llmConvListObj[llmConvListCurrId].msgList" :key="item.id"
                                 :ref="'msgItem_' + index">
                                <div class="fc chat-msg-time" v-if="item.isShowTime">{{formatConvTime(item.sendTime)}}</div>
                                <div class="fr chat-msg-item chat-msg-send" v-if="item.sendId == userInfo.id">
                                    <div class="chat-msg-wrapper">
                                        <div class="fl chat-msg-content">{{item.msgContent}}</div>
                                        <div class="fr chat-msg-state">
<!--                                            <div v-if="item.msgState == 0" class="state0">未读</div>-->
<!--                                            <div v-if="item.msgState == 1" class="state1">已读</div>-->
                                        </div>
                                    </div>
                                    <img :src="userInfo.avatarImg" class="chat-msg-avatar" v-if="userInfo.avatarImg" />
                                    <div class="chat-msg-avatar friend-avatar-text fc" v-if="!userInfo.avatarImg">{{userInfo.nickname.substring(0,1).toUpperCase()}}</div>
                                </div>
                                <div class="fl chat-msg-item chat-msg-recv" v-if="item.sendId != userInfo.id">
<!--                                    <img :src="friendObj[item.sendId].friendIcon" class="chat-msg-avatar" v-if="friendObj[item.sendId].friendIcon" />-->
<!--                                    <div class="chat-msg-avatar friend-avatar-text fc" v-if="!friendObj[item.sendId].friendIcon">{{friendObj[item.sendId].friendName.substring(0,1).toUpperCase()}}</div>-->
                                    <div class="chat-msg-avatar friend-avatar-text fc">AI</div>
                                    <div class="chat-msg-wrapper">
                                        <div class="fl chat-msg-name">AI小助手</div>
                                        <div class="fl chat-msg-content">{{item.msgContent}}</div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="fc chat-conv-msg-wrapper" v-else>
                        <div class="fc">开始对话吧～</div>
                    </div>
                    <div class="chat-conv-form">
                        <div class="fb chat-conv-tool">
                            <div class="fl">
                                <div class="chat-conv-tool-item"><i class="el-icon-picture-outline chat-conv-tool-btn"></i></div>
                                <div class="chat-conv-tool-item"><i class="el-icon-chat-dot-round chat-conv-tool-btn"></i></div>
                            </div>
                            <div class="fl">
                                <div style="color:#ccc;font-size: 14px;">使用Enter键发送消息</div>
                            </div>
                        </div>
                        <div class="chat-conv-input" contenteditable="true" placeholder="按回车键可以发送"  @input="llmInputUpdate" @compositionstart="chatCompositionStart" @compositionend="chatCompositionEnd"  @keydown="llmInputEnter" ref="llmInput"></div>
                    </div>
                </div>
                <div class="chat-content-friend" v-if="currNav == 'friend'">
                    <div class="friend-detail" v-if="currFriendDetail.id">
                        <div class="fl friend-detail-user">
                            <img v-if="currFriendDetail.friendAvatarImg" :src="currFriendDetail.friendAvatarImg" class="friend-detail-avatar"  />
                            <div v-else class="friend-detail-avatar friend-detail-avatar-text fc" >{{currFriendDetail.friendName.substring(0,1).toUpperCase()}}</div>
                            <i v-if="currFriendDetail.friendSexEm == 2" class="el-icon-user-solid" style="margin-left:10px;font-size: 32px;color:#f37e7d;"></i>
                            <i v-if="currFriendDetail.friendSexEm == 1" class="el-icon-user-solid" style="margin-left:10px;font-size: 32px;color:#45b6ef;"></i>
                            <i v-if="currFriendDetail.friendSexEm == 0" class="el-icon-user-solid" style="margin-left:10px;font-size: 32px;color:#ccc;"></i>
                            <div class="friend-detail-name">{{currFriendDetail.friendAlias ? currFriendDetail.friendAlias : currFriendDetail.friendName}}</div>
                        </div>
                        <div class="fc friend-detail-tochat"><el-button type="primary" @click="tapCreateConv">发消息</el-button></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <el-dialog title="添加好友"  :close-on-click-modal="false" :visible.sync="showAddFriendDialog" width="500">
        <div class="fl friend-add-dialog-search">
            <el-input size="mini" prefix-icon="el-icon-search" ref="searchNewFriendVal" clearable @keyup.enter.native="tapFriendAddSearch" placeholder="搜索好友" v-model="searchNewFriendVal" style="margin-right:10px;"></el-input>
            <el-button size="mini"  type="primary" class="conv-search-add" @click="tapFriendAddSearch">搜索</el-button>
        </div>
        <div class="friend-add-search-list">
            <div class="friend-list">
                <div class="fb friend-item" v-for="item in friendAddSearchList" :key="item.id">
                    <div class="fl">
                        <img :src="item.friendAvatarImg" class="friend-avatar" v-if="item.friendAvatarImg" />
                        <div class="friend-avatar friend-avatar-text fc" v-if="!item.friendAvatarImg">{{item.nickname.substring(0,1).toUpperCase()}}</div>
                        <div class="friend-name">{{item.nickname}}</div>
                    </div>
                    <el-tag effect="plain" class="btn" v-if="item.stateEm == 0" @click="tapCreateAddFriendApply(item)">添加</el-tag>
                    <el-tag effect="plain" class="btn" v-if="item.stateEm == 1" @click="tapCreateAddFriendApply(item)">待验证</el-tag>
                    <el-tag type="warning"  v-if="item.stateEm == 99" >本人</el-tag>
                    <el-tag type="success" effect="plain" v-if="item.stateEm == 2">好友</el-tag>
                    <el-tag type="info" class="btn" v-if="item.stateEm == -2"  @click="tapCreateAddFriendApply(item)">对方拒绝</el-tag>
                </div>
                <div class="fc search-result" v-if="friendAddSearchListState != ''">
                    <div v-loading="loading" class="fc search-loading" v-if="friendAddSearchListState == 'loading'"></div>
                    <div class="fc" v-if="friendAddSearchListState == 'none'">未搜索到信息</div>
                </div>

            </div>
        </div>
    </el-dialog>

    <el-dialog title="好友申请列表"  :close-on-click-modal="false" :visible.sync="friendNewApplyShow" width="500">
        <div class="friend-add-search-list" v-infinite-scroll="getRecvFriendApplyList" infinite-scroll-disabled="recvFriendApplyListState != '' && recvFriendApplyListState != 'error'">
            <div class="friend-list">
                <div class="fb friend-item" v-for="(item,index) in recvFriendApplyList" :key="item.id">
                    <div class="fl">
                        <img :src="item.friendAvatarImg" class="friend-avatar" v-if="item.userAvatarImg" />
                        <div class="friend-avatar friend-avatar-text fc" v-if="!item.userAvatarImg">{{item.userName.substring(0,1).toUpperCase()}}</div>
                        <div class="friend-name">{{item.userName}}</div>
                    </div>
                    <div class="fr" v-if="item.stateEm == 1">
                        <el-tag effect="plain" class="btn" @click="tapOperateFriendApply(index,1)">通过</el-tag>
                        <el-tag type="danger" style="margin-left:10px;" effect="plain" class="btn"  @click="tapOperateFriendApply(index,-1)">拒绝</el-tag>
                    </div>

                    <el-tag effect="plain" type="success"  v-if="item.stateEm == 2">已通过</el-tag>
                    <el-tag effect="plain" type="info" v-if="item.stateEm == -2">已拒绝</el-tag>
                </div>
                <div class="fc search-result" v-if="recvFriendApplyListState != ''">
                    <div v-loading="loading" class="fc search-loading" v-if="recvFriendApplyListState == 'loading'"></div>
                    <div class="fc" v-if="recvFriendApplyListState == 'none'">未查询到信息</div>
                </div>

            </div>
        </div>
    </el-dialog>
</div>
<script src="static/js/vue.js"></script>
<script src="static/js/element.js"></script>
<script src="static/js/axios.js"></script>
<script src="static/js/tool.js"></script>
<script src="static/js/request.js"></script>
<!--需要在http环境下才可以用，现在双击打开就先不启用了-->
<!--<script src="static/js/sql-wasm.js"></script>-->
<script>
    const MsgClasEmChat = 1
    const MsgClasMarkRead = 2
    const MsgClasEmNewFriendApply = 4
    const MsgClasEmNewFriendOperated = 5
    const MsgClasMarkSend = 6
    var apiImUrl = "http://localhost:8812"
    var apiUserUrl = "http://localhost:8801"
    var wsUrl = "http://localhost:8808"
    var appToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzY1NjE2ODgsImlhdCI6MTczMDUxMzY4OCwicGxhdENsYXNFbSI6MSwicGxhdElkIjoiMSJ9.OhwMM4l_UHtIXqzDFLtRNsattHAtkFuNgBZisf2N6Zw'
    // var difyApiKey = 'app-8Fxi5VMcFez2UwyBnPnYcJhX' //本地
    // var difyUrl = 'http://127.0.0.1:8070/v1' // 本地
    // var difyUrl = 'http://localhost:8089/v1' //gin后端
    // var difyApiKey = 'app-NPbrmyq5ACrvCPEHJQiRVuM5' //gin后端
    var difyUrl = 'http://localhost:8824/v1' //gozero后端
    var difyApiKey = 'app-NPbrmyq5ACrvCPEHJQiRVuM5' //gozero后端
    var isGozero = true
    function throttle(func, limit) {
        let inThrottle;
        return function(...args) {
            const context = this;
            if (!inThrottle) {
                func.apply(context, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        };
    }
    new Vue({
        el: '#app',
        data() {
            return {
                db:null,
                headers:{
                    token:'',
                    Authorization:appToken
                },
                difyHeaders:{Authorization:'Bearer '+difyApiKey},
                isConvInitScroll:false,
                unreadConvTotal:0,
                unreadNewGroupApply:0,
                isCloudHis:true,
                userInfo:{},
                myMsgReadUcode:'',
                conn:null,
                connHeartT:null,
                connectState:0,
                userToken:'',
                currNav:'conv',
                searchConvVal:'',
                showConvDrawer:false,
                showChatWindowMoreBottom:false,
                vshowChatWindowMoreTop:false,
                convList:[],
                llmConvList:[],
                llmConvListObj:{},
                llmConvListCurrId:'',
                llmSendChatState:0,//0无发送，1有发送
                llmTempMsg:'',//无会话时的临时对话存储信息
                activeConvIndex:-1,
                activeLlmConvIndex:-1,
                activeFriendIndex:-1,
                searchFriendVal:'',
                searchNewFriendVal:'',
                currFriendDetail:{},
                friendList:[],
                friendObj:{},
                showAddFriendDialog:false,
                friendAddSearchList:[],
                friendAddSearchListState:'',
                friendNewApplyShow:false,
                recvFriendApplyList:[],
                recvFriendApplyListState:'',
                recvFriendApplyListNextPage:1,
                unreadNewFriendApply:0,
                isChatComposing:false,
                searchGroupVal:'',
                groupList:[],
                showAddGroupDialog:false,
                groupAddSearchList:[],
                groupAddSearchListShowNone:false,
                readQueue: new Set(), // 用于存储需要标记已读的消息
                scrollTimeout: null   // 用于记录滚动停止的定时器

            }
        },
        created(){
            this.login()
            //this.initSqlite() //使用sqlite时需要http换进，并引入上面注释的js文件
        },
        mounted() {
            this.$refs.app.style.display = "block"
        },
        beforeDestroy() {
        },
        methods: {
            initSqlite() {
                initSqlJs({
                    locateFile: file => `/static/js/${file}`  // 指定 wasm 文件的路径
                }).then(SQL => {
                    this.initDB(SQL);
                });
            },
            login() {
                let urlParams = new URLSearchParams(window.location.search);
                if (!urlParams.get('token')) {
                    tool.toastError("缺少token")
                    return
                }
                this.headers.token = urlParams.get('token')
                this.getUserInfo()
                this.getMyFriendList()
                //云消息记录时，获取会话列表
                if (this.isCloudHis) {
                    this.getMyCloudConvList()
                }
                this.getMySysMsgUnreadList()
                this.connectWs()

            },
            connectWs() {
                this.conn = new WebSocket(wsUrl + "/ws", this.headers.token);
                this.conn.onopen = () => {
                    this.connectState = 2
                    clearInterval(this.connHeartT);
                    this.connHeartT = setInterval(() => {
                        this.heartPing()
                    }, 300 * 1000)
                }
                this.conn.onclose = () => {
                    this.connectState = -1
                };
                this.conn.onmessage = (e) => {
                    let msg = JSON.parse(e.data);
                    switch (msg.frameType) {
                        case 9:
                            tool.toastError(msg.data.msg)
                            break
                        case 0:
                            this.recvMsgHanler(msg)
                    }

                };
                this.conn.onerror = function (evt) {
                    console.error(evt.message, evt.reason, evt.code)
                };

            },
            heartPing() {
                let msgData = {"frameType": 1}
                if (this.conn.readyState === WebSocket.OPEN) {
                    this.sendMsg(msgData)
                } else {
                    // WebSocket 已关闭或正在关闭，重新连接
                    this.connectWs();
                    // 等待连接成功后再发送消息
                    setTimeout(() => this.sendMsg(msgData), 3000);
                }
                // 重连机制不知道怎么才好，现在写的都有瑕疵，会重复定时器
                // let msgData = {"frameType":1}
                // if (this.conn.readyState === WebSocket.OPEN) {
                //     this.conn.send(JSON.stringify(msgData));
                // } else if (this.conn.readyState === WebSocket.CONNECTING) {
                //     // 如果 WebSocket 正在连接中，稍后再尝试发送消息
                //     setTimeout(() => this.sendMsg(msgData), 5000);
                // } else {
                //     // WebSocket 已关闭或正在关闭，重新连接
                //     this.connectWs();
                //     // 等待连接成功后再发送消息
                //     setTimeout(() => this.sendMsg(msgData), 5000);
                // }
            },
            sendMsg(msgData) {
                this.conn.send(JSON.stringify(msgData));
                //this.saveLocal(msgData.data)
            },
            //将消息记录缓存到本地sqlite
            saveLocal(chatLog) {
                chatLog.conversationId = this.convList[this.activeConvIndex].conversationId
                // 数据库中实际存在的字段名
                const validColumns = ['id', 'conversationId', 'sendId', 'recvId', 'sendAtMs', 'chatType', 'msgType',
                    'msgContent', 'sendTime', 'msgState', 'msgReads', 'tempId', 'platId', 'updateAt', 'createAt'];

                // 过滤掉 chatLog 对象中那些不在 validColumns 列表中的字段
                const keys = Object.keys(chatLog).filter(key => validColumns.includes(key));
                const values = keys.map(key => chatLog[key]);

                // 如果 keys 或 values 为空，直接返回
                if (keys.length === 0 || values.length === 0) {
                    console.error("No valid fields to insert");
                    return;
                }

                // 构建 INSERT 语句
                const insertQuery = `
                    INSERT INTO chatLog (${keys.join(', ')})
                    VALUES (${keys.map(() => '?').join(', ')})`;

                // 处理 undefined 的情况，替换为合适的默认值
                const processedValues = values.map(value => {
                    if (value === undefined) {
                        return ''; // 或者根据需要返回 null, 0, etc.
                    }
                    return value;
                });

                try {
                    const stmt = this.db.prepare(insertQuery);
                    stmt.run(processedValues);
                    stmt.free();
                    this.saveDatabaseToIndexedDB(this.db)
                } catch (error) {
                    console.error("Error executing insert statement:", error);
                }

            },
            //从sqlite里查询消息记录
            queryChatLogs(conversationId, page, pageSize) {
                const offset = (page - 1) * pageSize;
                const stmt = this.db.prepare(`
                    SELECT *
                    FROM chatlog
                    WHERE conversationId = ?
                    ORDER BY sendAtMs DESC LIMIT ?
                    OFFSET ?
                `);
                const results = [];
                stmt.bind([conversationId, pageSize, offset]);
                while (stmt.step()) {
                    results.push(stmt.getAsObject());
                }

                stmt.free();
                return results;
            },
            // 将sqlite数据持久化到IndexedDB
            saveDatabaseToIndexedDB(db) {
                const indexedDBRequest = indexedDB.open("sqlite_database", 1);
                indexedDBRequest.onupgradeneeded = (event) => {
                    const db = event.target.result;
                    if (!db.objectStoreNames.contains("databases")) {
                        db.createObjectStore("databases");
                    }
                };

                indexedDBRequest.onsuccess = (event) => {
                    const indexedDB = event.target.result;
                    const transaction = indexedDB.transaction(["databases"], "readwrite");
                    const objectStore = transaction.objectStore("databases");

                    // 使用SQL.js库的.serialize方法导出数据库为Uint8Array格式
                    const binaryArray = db.export()

                    // 将导出的数据库二进制数据保存到IndexedDB中
                    objectStore.put(binaryArray, "sqlite.db");

                    transaction.oncomplete = () => {
                        console.log("数据库保存到IndexedDB成功");
                    };

                    transaction.onerror = (event) => {
                        console.error("数据库保存到IndexedDB失败", event);
                    };
                };

                indexedDBRequest.onerror = (event) => {
                    console.error("打开IndexedDB失败", event);
                };
            },

            // 从 IndexedDB 恢复sqlite数据库
            initDB(SQL) {
                const indexedDBRequest = indexedDB.open("sqlite_database", 1);
                indexedDBRequest.onsuccess = (event) => {
                    const indexedDB = event.target.result;
                    const transaction = indexedDB.transaction(["databases"], "readonly");
                    const objectStore = transaction.objectStore("databases");
                    const getRequest = objectStore.get("sqlite.db");

                    getRequest.onsuccess = (event) => {
                        const binaryArray = event.target.result;
                        console.log(SQL, binaryArray)
                        if (binaryArray) {
                            // 从 IndexedDB 中读取到的二进制数据初始化 SQLite 数据库
                            const db = new SQL.Database(new Uint8Array(binaryArray));
                            this.db = db; // 将 db 实例存储到 Vue 组件的实例属性中

                            console.log("数据库从 IndexedDB 成功加载并初始化");
                        } else {
                            console.log("没有找到已保存的数据库，可能是第一次加载");
                            this.db = new SQL.Database(); // 如果没有数据，创建一个新的空数据库
                            //使用 TEXT 类型存储 MongoDB 的 ObjectID
                            //使用 INTEGER 类型存储时间戳
                            //使用 BLOB 类型存储字节数组
                            this.db.run(`
                                CREATE TABLE IF NOT EXISTS chatLog (
                                    id TEXT PRIMARY KEY,
                                    conversationId TEXT NOT NULL DEFAULT '',
                                    sendId TEXT NOT NULL DEFAULT '',
                                    recvId TEXT NOT NULL DEFAULT '',
                                    sendAtMs INTEGER NOT NULL DEFAULT 0,
                                    chatType INTEGER NOT NULL DEFAULT 0,
                                    msgType INTEGER NOT NULL DEFAULT 0,
                                    msgContent TEXT,
                                    sendTime TEXT NOT NULL DEFAULT '',
                                    msgState INTEGER NOT NULL DEFAULT 0,
                                    msgReads BLOB,
                                    tempId TEXT NOT NULL DEFAULT '',
                                    platId TEXT NOT NULL DEFAULT '',
                                    updateAt TEXT NOT NULL DEFAULT '',
                                    createAt TEXT NOT NULL DEFAULT ''
                                );
                            `);
                        }
                    };

                    getRequest.onerror = (event) => {
                        console.error("从 IndexedDB 读取数据库失败", event);
                    };
                };

                indexedDBRequest.onerror = (event) => {
                    console.error("打开 IndexedDB 失败", event);
                };
            },
            recvMsgHanler(msg) {
                if (!msg.data) return console.log("异常消息：", msg)
                switch (msg.data.msgClas) {
                    case MsgClasEmNewFriendApply: //新好友申请
                        this.recvMsgNewFriendApply()
                    case MsgClasEmNewFriendOperated:
                        this.recvFriendApplyOperated(msg.data)
                    case MsgClasEmChat:
                        if (msg.data.chatType == 2) {
                            this.recvChatSingleMsg(msg.data)
                        }
                    case MsgClasMarkRead:
                        this.recvChatMsgRead(msg.data)
                    case MsgClasMarkSend:
                        this.recvChatMsgSend(msg.data)
                }
            },
            //标记正在输入拼音，用于避免回车输入文字导致提交消息
            chatCompositionStart() {
                this.isChatComposing = true;
            },
            //标记结束输入拼音，用于避免回车输入文字导致提交消息
            chatCompositionEnd() {
                this.isChatComposing = false;
            },
            //标记消息发送，将消息id返回给前端
            recvChatMsgSend(data) {
                ///目前没想好这块标记怎么做，实际没有这个业务触发
                let index = -1
                // 查找当前已读标记所在的会话
                for (let i = 0;i < this.convList.length;i++){
                    if (this.convList[i].conversationId == data.conversationId){
                        index = i
                        break
                    }
                }
                if (index == -1 || !this.convList[index].msgList) return
                for (let i = 0 ; i < this.convList[index].msgList.length;i++){
                    if (this.convList[index].msgList[i].tempId == data.tempId){
                        this.convList[index].msgList[i].id = data.msgId
                        break
                    }
                }
                console.log('发送消息到服务器了',data)
            },
            recvChatMsgRead(data) {
                //如果是纯前端缓存，应该直接从本地数据库里好到这条信息，更新数据，但现在是网页版有点麻烦，全缓存占用内存高，消息记录是打开会话才会获取，所以当前只根据会话当前是否打开来处理，未开的会话反正会获取消息
                if (!data.readRecords) return
                let index = -1
                // 查找当前已读标记所在的会话
                for (let i = 0;i < this.convList.length;i++){
                    if (this.convList[i].conversationId == data.conversationId){
                        index = i
                        break
                    }
                }
                if (index == -1) return
                console.log('触发已读',data,this.uidToCode(this.userInfo.id))
                if (data.chatType == 2){
                    //私聊会话已读
                    let ucode = this.uidToCode(this.convList[index].targetId)
                    console.log('触发已读22',this.convList[index])
                    //找到要标记已读的消息
                    for (let msgId in data.readRecords){
                        //更新消息已读状态
                        if (data.readRecords[msgId][ucode] == 1){
                            console.log('触发了333')
                            let msgIndex = this.convList[index].msgList.findIndex(item => item.id == msgId)
                            console.log(msgIndex)
                            if (msgIndex > -1){
                                //this.convList[index].msgContent[msgIndex].readUsers = {}
                                //this.convList[index].msgContent[msgIndex].readUsers[ucode] = 1
                                this.$set(this.convList[index].msgList[msgIndex], 'readUsers', data.readRecords[msgId])
                                console.log('触发了',data.readRecords)
                            }
                        }
                    }
                }



            },
            recvChatSingleMsg(data) {
                //先从会话里找
                for (let i = 0; i < this.convList.length; i++) {
                    if (this.convList[i].conversationId == data.conversationId) {
                        this.convList[i].total++
                        this.convList[i].unread++
                        this.convList[i].lastAtMs = data.sendAtMs
                        this.convList[i].lastMsg = data
                        this.convList[i].msgList.push(data)
                        this.convList[i].isShow = true
                        let [targetObj] = this.convList.splice(i, 1);
                        // 将目标对象插入到数组的第一个位置
                        this.convList.unshift(targetObj);
                        //如果当前是激活状态，刷新界面，并且更新未读状态
                        if (this.activeConvIndex == i) {
                            this.$nextTick(() => {
                                if (this.$refs.chatConvMsgWindow.scrollHeight - this.$refs.chatConvMsgWindow.scrollTop - this.$refs.chatConvMsgWindow.offsetHeight > 100) {
                                    // 滚动条距离底部超过100
                                    this.showChatWindowMoreBottom = true
                                } else {
                                    this.$refs.chatConvMsgWindow.scrollTop = this.$refs.chatConvMsgWindow.scrollHeight
                                }
                            })
                            this.tapConvItem(i)
                        }
                        return
                    }
                }
                //没找到，从好友列表里找，创建会话
                for (let i = 0; i < this.friendList.length; i++) {
                    if (this.friendList[i].friendUid == data.sendId) {
                        this.convList.unshift({
                            chatType: 2,
                            conversationId: data.conversationId,
                            isShow: true,
                            lastAtMs: data.sendAtMs,
                            lastMsg: data,
                            targetId: data.sendId,
                            msgList: [data],
                            total: 1,
                            readSeq: 0,
                            unread: 1,
                        });
                        return
                    }
                }
            },
            tapChatWindow(e) {
                if (
                    this.showConvDrawer &&
                    this.$refs.convDrawer &&
                    !this.$refs.convDrawer.contains(e.target) &&
                    !this.$refs.convDrawerBtn.contains(e.target) &&
                    !this.$refs.chatNav.contains(e.target)

                ) {
                    this.showConvDrawer = false;
                }
            },
            tapDelConv() {
                if (!this.convList[this.activeConvIndex].conversationId) {
                    return this.removeCurrConvItem()
                }
                this.$confirm('删除聊天将会清空聊天记录, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    request({
                        url: apiImUrl + '/im/v1/conversation/deleteMyConv',
                        headers: this.headers,
                        data: {
                            id: this.convList[this.activeConvIndex].conversationId
                        }
                    }).then(res => {
                        this.removeCurrConvItem()
                    })
                }).catch(() => {


                });
            },
            uidToCode(uid) {
                const base64Charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
                let decimal = BigInt(uid);
                let base64Str = "";

                if (decimal === 0n) return "0";

                while (decimal > 0n) {
                    let remainder = decimal % 64n;
                    base64Str = base64Charset[Number(remainder)] + base64Str;
                    decimal = decimal / 64n;
                }

                return base64Str;
            },

            //移除当前选中的会话
            removeCurrConvItem(){
                this.convList.splice(this.activeConvIndex,1)
                this.activeConvIndex = -1
                if (this.showConvDrawer) this.showConvDrawer = false
            },
            recvMsgNewFriendApply(){
                this.getMySysMsgUnreadList()
            },
            recvFriendApplyOperated(data){
                this.getMyFriendList()
            },
            tapNav(nav){
                if (nav == "logout"){
                    location.href="./home.html"
                    return
                }
                this.currNav = nav
            },
            getMyCloudConvList(){
                request({
                    url:apiImUrl + '/im/v1/conversation/getConversationList',
                    headers:this.headers,
                }).then(res=>{
                    let convList = []
                    for (let k in res.conversations){
                        let conv = res.conversations[k]
                        conv.msgList = []
                        convList.push(conv)
                    }
                    convList.sort((a, b) => b.lastAtMs - a.lastAtMs);
                    this.convList = convList
                })
            },
            tapShowConvAdd(){

            },
            tapLlmConvItem(index){
                this.llmConvListCurrId = this.llmConvList[index].id
                this.activeLlmConvIndex = index
                this.getLlmConvDetail(this.llmConvList[index])
            },
            getLlmConvDetail(conv){
                this.llmConvListObj[this.llmConvListCurrId].msgList = []
                axios({
                    url:difyUrl + '/messages',
                    headers:this.difyHeaders,
                    method:'get',
                    params: {
                        user:this.userInfo.id,
                        conversation_id:conv.id
                    }
                }).then(res=>{
                    let list = []
                    res.data.data.forEach(item=>{
                        list.push({
                            chatType: 2,
                            recvId:'dify_app_id1',
                            sendId:this.userInfo.id,
                            tempId: item.id+'_q', // 临时id，时间戳+9位长度的随机数,
                            sendAtMs:item.created_at*1000 , //先用来显示消息时间排序用，
                            msgContent: item.query,
                            msgType:1,
                            msgState:0,//刚发的，未读状态
                        })
                        list.push({
                            chatType: 2,
                            recvId:this.userInfo.id,
                            sendId:'dify_app_id1',
                            tempId: item.id+'_a', // 临时id，时间戳+9位长度的随机数,
                            sendAtMs:item.created_at*1000 , //先用来显示消息时间排序用，
                            msgContent: item.answer,
                            msgType:1,
                            msgState:0,//刚发的，未读状态
                        })
                    })
                    this.llmConvListObj[this.llmConvListCurrId].msgList = list
                })
            },
            sendLlmMsg(){
                if (this.llmSendChatState == 1){
                    return tool.toast('请先等待回复完成')
                }
                let content = this.$refs.llmInput.innerText.trim()
                if (content == "") return
                this.$refs.llmInput.innerText = ''
                let currConv = {}
                if (this.llmConvListCurrId){
                    this.llmConvListObj[this.llmConvListCurrId].inputMsg = ''
                    currConv = this.llmConvListObj[this.llmConvListCurrId]
                } else {
                    this.llmConvListCurrId = 'temp'
                    currConv ={
                        chatType:2,
                        conversationId:'',
                        isShow:true,
                        lastAtMs:Date.now(),
                        lastMsg:'',
                        targetId:'dify_app_id1',
                        msgList:[],
                        seq:0,
                        total:0
                    }
                }
                this.llmSendChatState = 1
                let msgData = {
                    chatType: 2,
                    recvId:'dify_app_id1',
                    sendId:this.userInfo.id,
                    tempId: Date.now() + '' + (Math.floor(Math.random() * 900000000) + 100000000), // 临时id，时间戳+9位长度的随机数,
                    sendAtMs:Date.now() , //先用来显示消息时间排序用，
                    msgContent: content,
                    msgType:1,
                    msgState:0,//刚发的，未读状态
                }
                currConv.msgList.push(msgData)
                currConv.lastMsg = msgData
                currConv.lastAtMs = msgData.sendAtMs
                currConv.seq++
                currConv.total++
                this.$set(this.llmConvListObj,this.llmConvListCurrId,currConv)
                let streamUrl = difyUrl + '/chat-messages'
                let headers = {
                    ...this.difyHeaders,
                    'Content-Type': 'application/json'
                }
                if (isGozero){
                    streamUrl = difyUrl + '/chatMessageStream'
                    headers['Authorization'] = appToken
                    console.log(this.userInfo)
                    headers['Token'] = this.headers.token
                }

                fetch(streamUrl, {
                    method: 'POST',
                    headers: headers,
                    body: JSON.stringify({
                        query: content,
                        inputs: {},
                        response_mode: "streaming",
                        user: this.userInfo.id,
                        conversation_id: this.llmConvListCurrId,
                        stream: true
                    })
                })
                    .then(async response => {
                        const reader = response.body.getReader();
                        const decoder = new TextDecoder('utf-8');
                        this.llmConvListObj[this.llmConvListCurrId].msgList.push({
                            chatType: 2,
                            recvId:this.userInfo.id,
                            sendId:'dify_app_id1',
                            tempId: Date.now() + '' + (Math.floor(Math.random() * 900000000) + 100000000), // 临时id，时间戳+9位长度的随机数,
                            sendAtMs:Date.now() , //先用来显示消息时间排序用，
                            msgContent: '回复：',
                            msgType:1,
                            msgState:0,//刚发的，未读状态
                        })
                        while (true) {
                            const { done, value } = await reader.read();
                            if (done) {
                                console.log("Stream finished.");
                                this.llmSendChatState = 0
                                break;
                            }
                            // 解析数据块
                            const chunk = decoder.decode(value, { stream: true });
                            // 移除 "data: " 前缀
                            if (chunk.substring(0,5) == 'data:'){
                                console.log(chunk.substring(6))
                                let msgData = JSON.parse(chunk.substring(6));
                                if (msgData.event == 'workflow_started'){
                                    console.log('工作流开始')
                                } else if (msgData.event =='workflow_finished'){
                                    console.log('工作流结束')
                                } else if (msgData.event =='node_started'){
                                    console.log(msgData.data.title + '开始')
                                } else if (msgData.event =='node_finished'){
                                    console.log(msgData.data.title + '结束')
                                } else if (msgData.event =='message'){
                                    console.log('aaaaaaaaaa',this.llmConvListObj[this.llmConvListCurrId])
                                    let lastMsg = this.llmConvListObj[this.llmConvListCurrId].msgList[this.llmConvListObj[this.llmConvListCurrId].msgList.length-1]
                                    let answer = lastMsg.msgContent +''+ msgData.answer
                                    this.$set(this.llmConvListObj[this.llmConvListCurrId].msgList[this.llmConvListObj[this.llmConvListCurrId].msgList.length-1],'msgContent',answer)
                                }
                                console.log(msgData)
                            } else {
                                console.log(chunk)
                            }

                            // 这里可以对 chunk 做进一步处理
                        }
                    })
                    .catch(error => {
                        console.error("Error:", error);
                        this.llmSendChatState = 0
                    });
            },
            sendChatMsg(){
                let content = this.$refs.chatInput.innerText.trim()
                if (content == "") return
                this.$refs.chatInput.innerText = ''
                this.convList[this.activeConvIndex].inputMsg = ''
                let msgData = {
                    chatType: 2,
                    recvId:this.convList[this.activeConvIndex].targetId,
                    sendId:this.userInfo.id,
                    tempId: Date.now() + '' + (Math.floor(Math.random() * 900000000) + 100000000), // 临时id，时间戳+9位长度的随机数,
                    sendAtMs:Date.now() , //先用来显示消息时间排序用，
                    msgContent: content,
                    msgType:1,
                    msgState:0,//刚发的，未读状态
                }
                let data = {
                    method: "conversation.chat",
                    data: msgData
                }
                //为了效率是可以缓存，但应该要设置上限，进入详情页再分页加载
                this.convList[this.activeConvIndex].msgList.push(msgData)
                this.convList[this.activeConvIndex].lastMsg = msgData
                this.convList[this.activeConvIndex].lastAtMs = msgData.sendAtMs
                this.convList[this.activeConvIndex].seq++
                this.convList[this.activeConvIndex].total++
                this.sendMsg(data)
                this.$nextTick(()=>{
                    this.$refs.chatConvMsgWindow.scrollTop = this.$refs.chatConvMsgWindow.scrollHeight
                })
            },
            tapFriendItem(index){
                this.activeFriendIndex = index
                this.currFriendDetail = this.friendList[index]
            },
            chatInputUpdate(e){
                this.convList[this.activeConvIndex].inputMsg = e.target.innerText;
            },
            llmInputUpdate(e){
                if (this.activeLlmConvIndex > 0){
                    this.llmConvList[this.activeLlmConvIndex].inputMsg = e.target.innerText;
                } else {
                    this.llmTempMsg = e.target.innerText;
                }

            },
            //点击会话列表中某个会话
            tapConvItem(index){
                //云消息记录，并且不是重复点击，获取历史记录
                if (this.isCloudHis && index != this.activeConvIndex){
                    //并且是需要有会话id的，不是刚创建的
                    if (this.convList[index].conversationId){
                        this.getChatMsgHisList(index)
                    }
                }
                this.isConvInitScroll = false
                //激活会话的请求，处理未读消息等
                this.setUpConv(index)
                //设置当前会话选中状态
                this.activeConvIndex = index
                //等渲染完毕，会话内容展示后，进行相关dom操作
                this.$nextTick(()=>{
                    //如果有暂存的输入内容，恢复到输入框中
                    if (this.convList[index].inputMsg) {
                        this.$refs.chatInput.innerText = this.convList[index].inputMsg
                        //让光标移动到最后位置
                        if (this.$refs.chatInput.innerText !== '')this.moveCursorToEnd(this.$refs.chatInput);
                    }
                    //输入框聚焦
                    this.$refs.chatInput.focus();
                    this.$nextTick(()=>{
                        //如果消息条数不够，没有触发滚动，就强行触发已读判断
                        if (!this.isConvInitScroll){
                            //这里如果不延迟的话，会因为还没渲染，msgList数据不对
                            setTimeout(()=>{
                                let markList = []
                                for (let i = 0;i < this.convList[this.activeConvIndex].msgList.length;i++){
                                    if (this.convList[this.activeConvIndex].msgList[i].msgState === 0 && this.convList[this.activeConvIndex].msgList[i].sendId != this.userInfo.id) {
                                        const msgElement = this.$refs['msgItem_' + index][0]; // 获取对应的 DOM 元素
                                        if (this.isElementInViewport(msgElement)) {
                                            markList.push(this.convList[this.activeConvIndex].msgList[i])
                                        }
                                    }
                                }
                                if (markList.length > 0){
                                    this.markAsRead(markList)
                                }

                            },100)

                        }
                    })
                })

            },
            onChatConvMsgListScroll(){
                this.isConvInitScroll = true
                const scrollTop = this.$refs.chatConvMsgWindow.scrollTop;
                const offsetHeight = this.$refs.chatConvMsgWindow.offsetHeight;
                const scrollHeight = this.$refs.chatConvMsgWindow.scrollHeight;
                // 检查是否距离底部 100px
                if (scrollHeight - scrollTop - offsetHeight <= 100) {
                    // 触发事件
                    this.onScrollNearBottom();
                }

                this.checkVisibleMessages();
                // 如果有未处理的计时器，先清除
                if (this.scrollTimeout) {
                    clearTimeout(this.scrollTimeout);
                }
                // 重新设置一个计时器，滚动停止后再触发最后一次处理
                this.scrollTimeout = setTimeout(() => {
                    this.forceMarkAsRead();
                }, 300); // 300ms 后触发
            },
            throttledMarkAsRead: throttle(function() {
                this.processReadQueue()
            }, 500), // 每500毫秒批量处理一次
            processReadQueue() {
                console.log("processReadQueue",this.readQueue)
                if (this.readQueue.size > 0) {
                    let list = []
                    this.readQueue.forEach(msg => {
                        list.push(msg)
                    });
                    this.markAsRead(list);
                    this.readQueue.clear();
                }
            },
            forceMarkAsRead() {
                // 强制执行最后一次标记已读
                this.processReadQueue();
            },
            isElementInViewport(el) {
                const rect = el.querySelector('.chat-msg-content').getBoundingClientRect(); // 获取消息内容的边界
                const containerRect = this.$refs.chatConvMsgWindow.getBoundingClientRect();

                return (
                    rect.top >= containerRect.top &&
                    rect.bottom <= containerRect.bottom &&
                    rect.bottom > containerRect.top && // 确保元素至少有部分是可见的
                    rect.top < containerRect.bottom    // 确保元素至少有部分是可见的
                );
            },
            checkVisibleMessages() {
                this.$nextTick(() => {
                    const msgList = this.convList[this.activeConvIndex].msgList;
                    msgList.forEach((msg, index) => {
                        // 使用节流的标记已读方法
                        this.throttledMarkAsRead(msg);
                        if (msg.msgState === 0 && msg.sendId != this.userInfo.id) {
                            const msgElement = this.$refs['msgItem_' + index][0]; // 获取对应的 DOM 元素
                            if (this.isElementInViewport(msgElement)) {
                                console.log('333333',msg)
                                this.readQueue.add(msg);
                            }
                        }
                    });
                });
            },
            markAsRead(msgList) {
                if (msgList) {
                    msgList.forEach(msg => {
                       // msg.msgState = 1; //调试用，先注释
                    });
                }
                this.sendReadStatusToServer(msgList);
            },
            sendReadStatusToServer(msgList){
                if (msgList.length == 0) return
                let msgData = {
                    chatType: 2,
                    conversationId:this.convList[this.activeConvIndex].conversationId,
                    recvId:this.convList[this.activeConvIndex].targetId,
                    msgIds:[]
                }
                msgList.forEach(item=>{
                    msgData.msgIds.push(item.id)
                })
                this.sendMsg({
                    method: "conversation.markRead",
                    data: msgData
                })
                console.log('触发标记已读',msgList)
            },

            tapChatWindowMoreBottom(){
                this.$refs.chatConvMsgWindow.scrollTop = this.$refs.chatConvMsgWindow.scrollHeight
            },
            onScrollNearBottom(){
                if (this.showChatWindowMoreBottom) this.showChatWindowMoreBottom =false
            },
            getChatMsgHisList(index){
                let conversationId = this.convList[index].conversationId
                request({
                    url:apiImUrl + '/im/v1/conversation/getChatLog',
                    headers:this.headers,
                    data:{
                        conversationId:conversationId,
                        startSendAt:Math.floor(Date.now() / 1000)
                    }
                }).then(res=>{
                    let convIndex  = this.convList.findIndex(item=>item.conversationId == conversationId)
                    if (convIndex == -1) console.log('会话不存在')
                    let total = res.list.length
                    console.log('本人code：',this.uidToCode(this.userInfo.id))
                    res.list.forEach((item,index)=>{
                        if (index > 0){
                            if (res.list[index-1].sendAtMs - item.sendAtMs > 300*1000) item.isShowTime = true
                        }
                        if (index+1 == total) item.isShowTime = true
                        if (item.sendId == this.userInfo.id){
                            //我发的消息，已读人里有对方，则为已读
                            let targetUcode =  this.uidToCode(item.recvId)
                            if (item.readUsers[targetUcode]) item.msgState = 1
                        } else if (item.recvId == this.userInfo.id){
                            //我收到的消息，已读人里有本人，则为已读
                            if (item.readUsers[this.myMsgReadUcode]) item.msgState = 1
                        }
                        this.convList[convIndex].msgList.unshift(item)
                    })
                    this.$nextTick(()=>{
                        this.$refs.chatConvMsgWindow.scrollTop = this.$refs.chatConvMsgWindow.scrollHeight
                    })
                })
            },
            setUpConv(index){
                //移除本地未读
                if (this.convList[index].unread > 0){
                    //先不做批量已读，根据滚动已读
                    //this.convList[index].unread = 0
                }
                //云同步窗口激活
                if (this.isCloudHis){
                    return request({
                        url:apiImUrl + '/im/v1/conversation/setUpMyConversation',
                        headers:this.headers,
                        data:{
                            recvId:this.convList[index].targetId,
                            chatType:this.convList[index].chatType,
                        }
                    })
                }

            },
            tapCreateConv(){
                this.currNav = "conv"
                this.tapConvByFriend(this.currFriendDetail)
            },
            chatInputEnter(e){
                if (!this.isChatComposing && e.key === 'Enter') {
                    if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
                        // 插入换行
                        document.execCommand('insertLineBreak');
                        e.preventDefault();
                    } else {
                        // 发送消息
                        e.preventDefault();
                        this.sendChatMsg();
                    }
                }
            },
            llmInputEnter(e){
                if (!this.isChatComposing && e.key === 'Enter') {
                    if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
                        // 插入换行
                        document.execCommand('insertLineBreak');
                        e.preventDefault();
                    } else {
                        // 发送消息
                        e.preventDefault();
                        this.sendLlmMsg();
                    }
                }
            },
            // 将光标移动到 contenteditable 元素的末尾
            moveCursorToEnd(element) {
                if (document.createRange && window.getSelection) {
                    const range = document.createRange();
                    const selection = window.getSelection();

                    range.selectNodeContents(element);
                    range.collapse(false); // false 表示将光标放在内容末尾

                    selection.removeAllRanges();
                    selection.addRange(range);
                } else {
                    // 兼容 IE9 和老旧浏览器
                    const range = document.body.createTextRange();
                    range.moveToElementText(element);
                    range.collapse(false);
                    range.select();
                }
            },
            tapConvByFriend(friendInfo){
                //先查找用户的会话是否存在
                let findIndex = this.convList.findIndex(obj => obj.targetId === friendInfo.friendUid);
                if (findIndex !== -1) {
                    // 将目标对象从数组中删除
                    let [targetObj] = this.convList.splice(findIndex, 1);
                    // 将目标对象插入到数组的第一个位置
                    this.convList.unshift(targetObj);
                } else {
                    this.convList.unshift({
                        chatType:2,
                        conversationId:'',
                        isShow:true,
                        lastAtMs:Date.now(),
                        lastMsg:'',
                        targetId:friendInfo.friendUid,
                        msgList:[],
                    });
                }
                this.$nextTick(()=>{
                    this.tapConvItem(0)
                })
            },
            getMySysMsgUnreadList(){
                request({
                    url:apiImUrl + '/im/v1/sysMsg/getMySysMsgUnreadNum',
                    headers:this.headers,
                }).then(res=>{
                    this.unreadNewFriendApply = res.unread && res.unread[4] ? res.unread[4] : 0
                })
            },
            getUserInfo(){
                request({
                    url:apiUserUrl + '/user/v1/getMyUserMainInfo',
                    headers:this.headers,
                }).then(res=>{
                    this.userInfo = res
                    this.myMsgReadUcode = this.uidToCode(res.id)
                    this.getMyLlmList()
                })
            },
            getMyFriendList(){
                request({
                    url:apiImUrl + '/social/v1/friend/getMyFriendList',
                    headers:this.headers,
                }).then(res=>{
                    this.friendList = res.list
                    let friendObj = {}
                    this.friendList.forEach((v,k)=>{
                        friendObj[v.friendUid] = v
                    })
                    this.friendObj = friendObj
                })
            },
            getMyLlmList(){
                axios({
                    url:difyUrl + '/conversations',
                    headers:this.difyHeaders,
                    params:{user:this.userInfo.id}
                }).then(res=>{
                    let llmConvList = []
                    let llmConvListObj = {}
                    res.data.data.forEach(v=>{
                        let conv = {
                            id:v.id,
                            name:v.name,
                            msgList:[]
                        }
                        llmConvList.push(conv)
                        llmConvListObj[v.id] = conv
                    })
                    this.llmConvList = llmConvList
                    this.llmConvListObj = llmConvListObj
                })
            },
            setNewFriendApplyRead(){
                request({
                    url:apiImUrl + '/im/v1/sysMsg/setMySysMsgReadByClas',
                    headers:this.headers,
                    data:{
                        msgClasEms:[MsgClasEmNewFriendApply],
                    }
                }).then(res=>{
                    this.unreadNewFriendApply = 0
                })
            },
            tapShowFriendNewApply(){
                this.friendNewApplyShow = true
                this.getRecvFriendApplyList(true)
            },
            getRecvFriendApplyList(isReload){
                if (isReload){
                    this.recvFriendApplyListNextPage = 1
                    this.recvFriendApplyList = []
                }
                this.friendAddSearchListState = "loading"
                request({
                    url:apiImUrl+'/social/v1/friend/getMyFriendApplyRecvPage',
                    headers:this.headers,
                    data:{
                        page:this.recvFriendApplyListNextPage,
                        size:20,
                    }
                }).then(res=>{
                    this.recvFriendApplyList = res.list
                    for (let i=0;i<res.list.length;i++){
                        if (res.list[i].stateEm == 1) { //存在未处理再消除已读
                            this.setNewFriendApplyRead()
                            break;
                        }
                    }
                    if (this.recvFriendApplyList.length == 0){
                        this.recvFriendApplyListState = 'none'
                    } else if(res.list.length == 0) {
                        this.recvFriendApplyListState = 'end'
                    } else {
                        this.recvFriendApplyListState = ''
                        this.recvFriendApplyListNextPage++
                    }
                }).catch(err=>{
                    this.recvFriendApplyListState = 'error'
                })
            },
            tapShowFriendAdd(){
                this.showAddFriendDialog = true
                this.searchNewFriendVal = ''
                this.friendAddSearchList = []
                this.friendAddSearchListState = ''
                this.$nextTick(()=>{
                    this.$refs.searchNewFriendVal.focus()
                })

            },
            tapFriendAddSearch(){
                if (this.searchNewFriendVal.trim() == '') return;
                this.friendAddSearchListState = "loading"
                request({
                    url:apiImUrl+'/social/v1/friend/searchNewFriendPage',
                    headers:this.headers,
                    data:{
                        keyword:this.searchNewFriendVal
                    }
                }).then(res=>{
                    this.friendAddSearchList = res.list
                    if (this.friendAddSearchList.length == 0){
                        this.friendAddSearchListState = 'none'
                    } else if(res.list.length == 0) {
                        this.friendAddSearchListState = 'end'
                    } else {
                        this.friendAddSearchListState = ''
                    }
                }).catch(err=>{
                    this.friendAddSearchListState = 'error'
                })

            },
            tapOperateFriendApply(index,state){
                if (state == 1) {
                    this.operateFriendApply(index,{
                        applyId:this.recvFriendApplyList[index].id,
                        operateStateEm:2,
                    })
                } else {
                    this.$prompt('请输入拒绝原因', '拒绝好友申请-'+this.recvFriendApplyList[index].userName, {
                        confirmButtonText: '提交',
                        cancelButtonText: '取消',
                        closeOnClickModal: false
                    }).then(({ value }) => {
                        this.operateFriendApply(index,{
                            applyId:this.recvFriendApplyList[index].id,
                            operateStateEm:-2,
                            operateMsg:value
                        })
                    })
                }
            },
            operateFriendApply(index,data){
                request({
                    url:apiImUrl+'/social/v1/friend/operateMyRecvFriendApply',
                    headers:this.headers,
                    loading:'提交中',
                    data
                }).then(res=>{
                    this.recvFriendApplyList[index].stateEm = data.operateStateEm
                    tool.toastSucc('提交成功')
                    if (data.operateStateEm == 2) {
                        this.getMyFriendList()
                    }
                })
            },
            tapCreateAddFriendApply(friend){
                this.$prompt('请输入验证消息', '添加好友申请-'+friend.nickname, {
                    confirmButtonText: '提交',
                    cancelButtonText: '取消',
                    closeOnClickModal: false
                }).then(({ value }) => {
                    request({
                        url:apiImUrl+'/social/v1/friend/createFriendApply',
                        headers:this.headers,
                        loading:'提交中',
                        data:{
                            applyMsg:value,
                            friendUid:friend.id,
                            sourceEm:1,// 1根据手机号搜索
                        }
                    }).then(res=>{
                        tool.toastSucc('提交成功')
                    })
                }).catch(() => {

                });

            },
            formatConvTime(timeMs){
                const inputDate = new Date(timeMs);
                const now = new Date();

                const inputDay = inputDate.getDate();
                const inputMonth = inputDate.getMonth() + 1;
                const inputYear = inputDate.getFullYear();

                const nowDay = now.getDate();
                const nowMonth = now.getMonth() + 1;
                const nowYear = now.getFullYear();

                const inputHours = inputDate.getHours().toString().padStart(2, '0');
                const inputMinutes = inputDate.getMinutes().toString().padStart(2, '0');

                // Same day
                if (inputYear === nowYear && inputMonth === nowMonth && inputDay === nowDay) {
                    return `${inputHours}:${inputMinutes}`;
                }

                // Yesterday
                const yesterday = new Date(now);
                yesterday.setDate(nowDay - 1);
                if (inputYear === yesterday.getFullYear() && inputMonth === (yesterday.getMonth() + 1) && inputDay === yesterday.getDate()) {
                    return `昨天 ${inputHours}:${inputMinutes}`;
                }

                // Other years
                if (inputYear !== nowYear) {
                    return `${inputYear}年${inputMonth}月${inputDay}日`;
                }

                // Other days in current year
                return `${inputMonth}月${inputDay}日`;
            }
        },
        computed:{
            friendListCpd(){
                let list = []
                this.friendList.forEach(item=>{
                    list.push(item)
                })
                return list
            },
        }
    })
</script>
</body>
</html>